package com.liujiajin.utils;

import com.liujiajin.dto.SensitiveWordDto;
import com.liujiajin.entity.TbSensitiveWordsExample;
import com.liujiajin.service.ISensitiveService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * DFA敏感词检测
 */
@Service
@Slf4j
public class DFAService implements InitializingBean {

    @Autowired
    private ISensitiveService sensitiveService;

    private final State startState = new State();
    @Override
    public void afterPropertiesSet() throws Exception {
        //1、从数据库查询敏感词
        TbSensitiveWordsExample tbsensitiveWordsExample = new TbSensitiveWordsExample();
        tbsensitiveWordsExample.setLimit(1000);
        List<SensitiveWordDto> sensitiveWordDtos = sensitiveService.queryByParam(tbsensitiveWordsExample);
        // 构建敏感词算法-DFA
        List<String> words= sensitiveWordDtos.stream().map(x -> x.getWord()).collect(Collectors.toList());
        addWords(words);
    }

    /**
     * 批量添加敏感词
     * @param words
     */
    private void addWords(List<String> words) {
        if(CollectionUtils.isEmpty( words)){
            return;
        }
        for(String word : words){
            addWord(word);
        }
    }

    /**
     * 单个添加敏感词
     * @param word
     */
    private void addWord(String word) {
        log.info("添加敏感词-DFAService-addWord-入参:{}", word);
        State currentState = startState;
        char[] charArray = word.toCharArray();
        for(char c : charArray){
            State  nextstate = currentState.nextState(c);
            if(nextstate == null){
                nextstate = new State();
                currentState.add(c, nextstate);
            }
            currentState = nextstate;
        }
        currentState.setTerminal(true);
    }

    /**
     * 敏感词匹配
     * 如果匹配到敏感词，把敏感词替换为*,否则返回原字符串
     */
    public String checkSensitiveWord(String word,char replacement){
        if(StringUtils.isEmpty(word)){
            return word;
        }
        StringBuilder result = new StringBuilder(word);
        int length = word.length();
        for(int i=0;i<length;){
            State currentState = startState;

            int j = i;
            while(j<length && currentState != null){
                currentState = currentState.nextState(word.charAt(j));
                //匹配到敏感词
                if(currentState!=null && currentState.isTerminal()){
                    // 替换敏感词
                    for(int k=i;k<=j;k++){
                        result.setCharAt(k,replacement);
                    }
                    i=j+1;
                    break;
                }
                j++;
            }
            if(currentState==null){
                i++;
            }
        }
        return result.toString();
    }

    private static class State{
        private final Map<Character, State> transitions= new HashMap<>();

        private boolean isTerminal = false;

        public State nextState(char c){
            return transitions.getOrDefault(c, null);
        }

        public void add(char c, State nextstate){
            transitions.put(c, nextstate);
        }

        public boolean isTerminal(){
            return isTerminal;
        }


        public void setTerminal(boolean terminal){
            isTerminal = terminal;
        }
    }
}
